package cmp.compile;

import java.io.*;
import java.sql.ResultSet;

import assem.Utils;
import assem.DBConn;
import cmp.main.Globals;
import cmp.compile.CompileMain;
import cmp.compile.MethodUserDef;
import cmp.compile.panels.CompilePanel;
import util.Debug.ErrorReport;
import util.methods.PaveProps;
import util.methods.Version;

public class MethodOrthoMCL {
	 String groupFile = "orthoMCL";  			// name of orthoMCL final output, usually orthoMCL
	
	 public boolean run(int idx, DBConn db, CompilePanel panel) {
		String comment = panel.getMethodComment(idx);
		String [] settings = panel.getMethodSettings(idx).split(":");

		prefix = panel.getMethodPrefix(idx);		// Groups should be prefixed with this
		inflation = settings[1];					// mcl parameter
		cmpDBC = db;
		cmpPanel = panel;
		blastFile = cmpPanel.getBlastPanel().getBlastFile();
		if (blastFile == null) return false;
		String x = inflation.replace(".", "");
		if (x.length()==1) x += "0";
		groupFile = cmpPanel.getCurrentProjectDirectory() 
				+ "/" + groupFile + "." + prefix + "-" + x;
		
		CompileMain.PrtDateMsg("\nStart execution of orthoMCL (downloaded from www.orthomcl.org)");	
		CompileMain.PrtSpMsg(1, "Prefix:     " + prefix);
		if (!comment.equals("")) CompileMain.PrtSpMsg(1, "Remark:    " + comment);
		CompileMain.PrtSpMsg(1, "Inflation:  " + inflation );
		CompileMain.PrtSpMsg(1, "Blast File: " + blastFile);	
		long startTime = CompileMain.getTime();
			
		doSteps(idx);
		
		// the following will load from file groupFile, i.e. orthoMCL is going to output to a file
		if (! new MethodUserDef().run(idx, groupFile, cmpDBC, cmpPanel)) return false;
		
		CompileMain.PrtDateMsgTime("Finish execution of orthoMCL", startTime);
		return true;
	}
	
	private void doSteps(int idx) {
	try{		 
		File OMCDir = new File(PaveProps.getExtDir() + "/OrthoMCL");
		File binDir = new File(OMCDir,"bin");
		String tempDB = "TMP_" + cmpPanel.getProjectName();
		ResultSet rs;
		
		if (!OMCDir.exists())
		{
			CompileMain.PrtError("Can't find OrthoMCL directory " + OMCDir.getAbsolutePath());
			return;		
		}
		if (!binDir.exists())
		{
			CompileMain.PrtError("Can't find OrthoMCL bin directory " + binDir.getAbsolutePath());
			return;		
		}
		
		File projDir = new File(cmpPanel.getCurrentProjectDirectory());
		
		// Directory for doing the work
		File tmpDir = new File(projDir,"OMCLTEMP");
		if (tmpDir.exists())
		{
			assem.Utils.clearDir(tmpDir);
		}
		else
		{
			tmpDir.mkdir();
		}
		File cfgFile = new File(tmpDir,"orthomcl.config");

		long startTime = CompileMain.getTime();
		CompileMain.PrtSpMsg(1, "Create OrthoMCL temporary database");
		rs = cmpDBC.executeQuery("show databases like '" + tempDB + "'");
		if (rs.first())
		{
			cmpDBC.executeUpdate("drop database " + tempDB);
		}
		DBConn odb = cmpDBC.createDBAndNewConnection(tempDB);
		
		// Write the cfg file used by OrthoMCL
		if (cfgFile.exists()) cfgFile.delete();
		BufferedWriter bw = new BufferedWriter(new FileWriter(cfgFile));
		bw.write("dbVendor=mysql\n");
		bw.write("dbConnectString=" + odb.getDbiStr() + "\n");
		bw.write("dbLogin=" + odb.mUser + "\n");
		bw.write("dbPassword=" + odb.mPass + "\n");
		bw.write("similarSequencesTable=SimilarSequences\n");
		bw.write("orthologTable=Ortholog\n");
		bw.write("inParalogTable=InParalog\n");
		bw.write("coOrthologTable=CoOrtholog\n");
		bw.write("interTaxonMatchView=InterTaxonMatch\n");
		bw.write("percentMatchCutoff=50\n");
		bw.write("evalueExponentCutoff=-5\n");
		bw.write("oracleIndexTblSpc=NONE\n");
		bw.close();

		// Schema install
		File schemInst = new File(binDir,"orthomclInstallSchema");
		String cmd = schemInst.getAbsolutePath() + " " + cfgFile.getAbsolutePath();
		System.out.println(cmd);
		assem.Utils.runCommand(cmd.split("\\s+"), tmpDir, false, true, null,0);

		File blastDir = new File(projDir, Globals.CompilePanel.BLASTDIR);
		File combFile = new File(blastDir, Globals.CompilePanel.COMBINEDFASTA);
		if (!combFile.exists() || combFile.length() < 10)
		{
			CompileMain.PrtWarn("Problem with Combined.fasta file - regenerating " + combFile.getAbsolutePath());
			CompileMain.generateFastaFromDB(cmpPanel);
			combFile = new File(blastDir, Globals.CompilePanel.COMBINEDFASTA);
			if (!combFile.exists())  {
				CompileMain.PrtError("Cannot generate Combined.fasta." );
				return;
			}
		}
		
		String blastFileStr = cmpPanel.getBlastPanel().getBlastFile();
		if (blastFileStr == null)
		{
			CompileMain.PrtError("No blast file! Generate blast file, then rerun." );
			return;
			
		}
		File blastFile = new File(blastFileStr); 
		if (!blastFile.exists())
		{
			CompileMain.PrtError("Can't find blast file " + blastFile.getAbsolutePath());
			return;
		}
		File tempFasta = new File(tmpDir,"fasta_temp");
		if (tempFasta.exists()) Utils.clearDir(tempFasta);
		else tempFasta.mkdir();
		Runtime.getRuntime().exec("ln -s " + combFile.getAbsolutePath() + " " + tempFasta.getAbsolutePath());

		long t = CompileMain.getTime();
		File ssFile = new File(tmpDir,"simSeq.txt");
		cmd = binDir.getAbsolutePath() + "/orthomclBlastParser " + blastFile.getAbsolutePath() + " " + tempFasta.getAbsolutePath();
		
		CompileMain.PrtSpMsg(2, "Running orthomclBlastParser");
		assem.Utils.runCommand(cmd.split("\\s+"), tmpDir, false, true, ssFile,0);
		CompileMain.PrtSpMsgTime(3, "Finish", t);

		t = CompileMain.getTime();
		cmd = binDir.getAbsolutePath() + "/orthomclLoadBlast " + cfgFile.getAbsolutePath() + " " + ssFile.getAbsolutePath();
		
		CompileMain.PrtSpMsg(2, "Running orthomclLoadBlast");
		assem.Utils.runCommand(cmd.split("\\s+"), tmpDir, false, true, null,0);
		CompileMain.PrtSpMsgTime(3, "Finish", t);	
		
		t = CompileMain.getTime();
		cmd = binDir.getAbsolutePath() + "/orthomclPairs " + cfgFile.getAbsolutePath() + " log-pairs cleanup=no";
		
		CompileMain.PrtSpMsg(2, "Running orthomclPairs");
		assem.Utils.runCommand(cmd.split("\\s+"), tmpDir, false, true, null,0);
		CompileMain.PrtSpMsgTime(3, "Finish", t);
		
		t = CompileMain.getTime();
		cmd = binDir.getAbsolutePath() + "/orthomclDumpPairsFiles " + cfgFile.getAbsolutePath();
		
		CompileMain.PrtSpMsg(2, "Running orthomclDumpPairsFiles");
		assem.Utils.runCommand(cmd.split("\\s+"), tmpDir, false, true, null,0);
		CompileMain.PrtSpMsgTime(3, "Finish", t);
		
		t = CompileMain.getTime();
		String inflVal = inflation;
		inflVal = cmpPanel.getMethodPanel().getSettingsAt(idx).split(":")[1];
		cmd = binDir.getAbsolutePath() + "/mcl mclInput --abc -I " + inflVal + " -o mclOutput";
		
		CompileMain.PrtSpMsg(2, "Running mcl");
		assem.Utils.runCommand(cmd.split("\\s+"), tmpDir, false, false, null,0);
		CompileMain.PrtSpMsgTime(3, "Finish", t);

		File finalOut = new File(groupFile);
		if (finalOut.exists()) finalOut.delete();
		
		File cshFile = new File(tmpDir,"final.csh");
		BufferedWriter cshW = new BufferedWriter(new FileWriter(cshFile));
		cmd = binDir.getAbsolutePath() + "/orthomclMclToGroups D 1 < mclOutput >" + finalOut.getAbsolutePath();
		CompileMain.PrtSpMsg(2, "Running orthomclMclToGroups");
		cshW.write(cmd + "\n");
		cshW.flush();cshW.close();
		
		cmd = "csh final.csh";
		assem.Utils.runCommand(cmd.split("\\s+"), tmpDir, false, false, null,0);
		
		CompileMain.PrtSpMsg(2, "Groups written to " + groupFile);
		CompileMain.PrtDateMsgTime("Finish running orthoMCL ", startTime);
		odb.close();
		cmpDBC.executeUpdate("drop database " + tempDB);
		Utils.deleteDir(tmpDir);
	}catch (Exception e) {ErrorReport.reportError(e, "Error in OrthoMCL"); }
	}
	
	private DBConn cmpDBC;			// database connection
	private CompilePanel cmpPanel;	// get all parameters from this
	
	static private String prefix;
	static private String inflation;
	static private String blastFile;
}
